package com.linkhub.oms.admin.modules.stock.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.linkhub.oms.admin.common.exception.ExceptionFactory;
import com.linkhub.oms.admin.modules.stock.domain.dto.ConfirmInboundDTO;
import com.linkhub.oms.admin.modules.stock.domain.dto.CreateInboundDTO;
import com.linkhub.oms.admin.modules.stock.enums.BusinessType;
import com.linkhub.oms.admin.modules.stock.enums.ProductType;
import com.linkhub.oms.common.enums.IEnumConvert;
import com.linkhub.oms.common.util.CacheKeyAssist;
import com.linkhub.oms.common.util.json.QtFastjsonUtil;
import com.linkhub.oms.component.redis.locker.DistributedLocker;
import com.linkhub.oms.dao.mapper.PassageStockFlowEntityMapper;
import com.linkhub.oms.dao.mapper.ProductStockEntityMapper;
import com.linkhub.oms.entity.PassageStockFlowEntity;
import com.linkhub.oms.entity.ProductStockEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Objects;

/**
 * @ClassName PassageStockFlowServiceImpl
 * @Description 在途库存管理
 * @Author XieYu
 * @Date 2024/6/25 21:59
 * @Version 1.0
 */
@Slf4j
@Service
public class PassageStockBizServiceImpl {

    @Resource
    private PassageStockFlowEntityMapper passageStockFlowMapper;
    @Resource
    private ProductStockEntityMapper productStockMapper;
    @Resource
    private DistributedLocker distributedLocker;

    private String lockKey( String userId, String skuId, String stashName ) {
        return CacheKeyAssist.getPassageStockUpdatedLockKey(userId, skuId, stashName);
    }


    /**
     * @return void
     * @Author XieYu
     * @Description 入库单创建逻辑
     * @Date 2024/7/3 23:08
     * @Param [createInbound]
     */
    @Transactional(rollbackFor = Exception.class)
    public void wmsInboundCreated( CreateInboundDTO createInbound ) {
        log.info("库存管理-入库单创建-在途流水-开始，{}", QtFastjsonUtil.toJSONString(createInbound));
        PassageStockFlowEntity passageStockFlowEntity = new PassageStockFlowEntity();
        passageStockFlowEntity.setUserId(createInbound.getUserId());
        passageStockFlowEntity.setSkuId(createInbound.getSkuId());
        passageStockFlowEntity.setStashName(createInbound.getStashName());
        passageStockFlowEntity.setAmount(createInbound.getSkuQuantity());
        passageStockFlowEntity.setBusinessType(IEnumConvert.valueOf(createInbound.getBusinessType(), BusinessType.class).getCode());
        passageStockFlowEntity.setBusinessNo(createInbound.getBusinessNo());
        passageStockFlowEntity.setType(ProductType.UNKNOW.getValue());

        passageStockFlowMapper.insert(passageStockFlowEntity);

        String lockKey = lockKey(createInbound.getUserId(), createInbound.getSkuId(), createInbound.getStashName());
        if (!distributedLocker.tryLock(lockKey)) {
            log.error("入库单创建更新在途流水时获取锁失败");
            throw ExceptionFactory.getI18nBizException("stock.passage.updated.concurrence.error");
        }
        try {
            // 更新商品库存状态表中的在途数量
            ProductStockEntity updateStock = new ProductStockEntity();
            updateStock.setUserId(createInbound.getUserId());
            updateStock.setSkuId(createInbound.getSkuId());
            updateStock.setStashName(createInbound.getStashName());

            LambdaQueryWrapper<ProductStockEntity> whereWrapper = new LambdaQueryWrapper<>();
            whereWrapper.eq(ProductStockEntity::getUserId, createInbound.getUserId());
            whereWrapper.eq(ProductStockEntity::getSkuId, createInbound.getSkuId());
            whereWrapper.eq(ProductStockEntity::getStashName, createInbound.getStashName());
            ProductStockEntity existStock = productStockMapper.selectOne(whereWrapper);
            if (Objects.isNull(existStock)) {
                // 插入一条新的记录
                updateStock.setPassageStock(createInbound.getSkuQuantity());
                productStockMapper.insert(updateStock);
            } else {
                updateStock.setPassageStock(existStock.getPassageStock() + createInbound.getSkuQuantity());
                whereWrapper.eq(ProductStockEntity::getPassageStock, existStock.getPassageStock());
                productStockMapper.update(updateStock, whereWrapper);
            }
        }finally {
            distributedLocker.unlock(lockKey);
        }
        log.info("库存管理-入库单创建-在途流水-结束");
    }


    @Transactional(rollbackFor = Exception.class)
    public void wmsInboundConfirm( ConfirmInboundDTO confirmInboundDTO ) {
        log.info("库存管理-入库单确认-在途流水-开始，{}", QtFastjsonUtil.toJSONString(confirmInboundDTO));

        PassageStockFlowEntity passageStockFlowEntity = new PassageStockFlowEntity();
        passageStockFlowEntity.setUserId(confirmInboundDTO.getUserId());
        passageStockFlowEntity.setSkuId(confirmInboundDTO.getSkuId());
        passageStockFlowEntity.setStashName(confirmInboundDTO.getStashName());
        passageStockFlowEntity.setAmount(-confirmInboundDTO.getSkuQuantity());
        passageStockFlowEntity.setBusinessType(BusinessType.PURCHASE_RECEIPT.getCode());
        passageStockFlowEntity.setBusinessNo(confirmInboundDTO.getInboundNo());
        passageStockFlowEntity.setType(IEnumConvert.valueOf(confirmInboundDTO.getType(), ProductType.class).getValue());

        String lockKey = lockKey(confirmInboundDTO.getUserId(), confirmInboundDTO.getSkuId(), confirmInboundDTO.getStashName());
        if (!distributedLocker.tryLock(lockKey)) {
            log.error("入库单确认更新在途流水时获取锁失败");
            throw ExceptionFactory.getI18nBizException("stock.passage.updated.concurrence.error");
        }

        int waitInboundAmount = passageStockFlowMapper.getWaitInboundAmount(BusinessType.PURCHASE_RECEIPT.getCode(), confirmInboundDTO.getInboundNo());
        if (waitInboundAmount < confirmInboundDTO.getSkuQuantity()) {
            log.error("库存管理-入库单确认-在途流水-异常，入库数量已超过待入库数，请检查，入库单：{}，原剩余在途数：{}，此次入库数：{}",
                    confirmInboundDTO.getInboundNo(), waitInboundAmount, confirmInboundDTO.getSkuQuantity());
            throw ExceptionFactory.getI18nBizException("stock.passage.amount.over");
        }
        passageStockFlowMapper.insert(passageStockFlowEntity);  // 入库
        try {
            LambdaQueryWrapper<ProductStockEntity> whereWrapper = new LambdaQueryWrapper<>();
            whereWrapper.eq(ProductStockEntity::getUserId, confirmInboundDTO.getUserId());
            whereWrapper.eq(ProductStockEntity::getSkuId, confirmInboundDTO.getSkuId());
            whereWrapper.eq(ProductStockEntity::getStashName, confirmInboundDTO.getStashName());
            ProductStockEntity existStock = productStockMapper.selectOne(whereWrapper);
            existStock.setPassageStock(existStock.getPassageStock() - confirmInboundDTO.getSkuQuantity());
            productStockMapper.updateById(existStock);
        }finally {
            distributedLocker.unlock(lockKey);
        }

//        // 待入库的大于此次入库的量，说明是部分入库，等于说明全部入库
//        boolean allConfirm = waitInboundAmount > confirmInboundDTO.getSkuQuantity() ? false : true;
//        log.info("库存管理-入库单确认-在途流水-是否全部入库：{}，订单ID：{}，待入库数量：{}，本次入库数量：{}",
//                allConfirm, confirmInboundDTO.getInboundNo(), waitInboundAmount, confirmInboundDTO.getSkuQuantity());
//        log.info("库存管理-入库单确认-在途流水-结束");
//        return allConfirm;
    }


    @Transactional(rollbackFor = Exception.class)
    public void cancelPassageStock( String inboundNo ) {
        // TODO 应该
        LambdaQueryWrapper<PassageStockFlowEntity> whereWrapper = new LambdaQueryWrapper();
        whereWrapper.eq(PassageStockFlowEntity::getBusinessNo, inboundNo);
        whereWrapper.eq(PassageStockFlowEntity::getBusinessType, BusinessType.PURCHASE_RECEIPT.getCode());
        List<PassageStockFlowEntity> passageStockFlows = passageStockFlowMapper.selectList(whereWrapper);

        PassageStockFlowEntity passageStockFlowEntity = new PassageStockFlowEntity();
//        passageStockFlowEntity.setStatus(0);    // 取消
        passageStockFlowMapper.update(passageStockFlowEntity, whereWrapper);

        ProductStockEntity updateStock = new ProductStockEntity();
        for (PassageStockFlowEntity passageStockFlow : passageStockFlows) {
            LambdaQueryWrapper<ProductStockEntity> stockWhereWrapper = new LambdaQueryWrapper<>();
            stockWhereWrapper.eq(ProductStockEntity::getSkuId, passageStockFlow.getSkuId());
            stockWhereWrapper.eq(ProductStockEntity::getStashName, passageStockFlow.getStashName());
            stockWhereWrapper.eq(ProductStockEntity::getUserId, passageStockFlow.getUserId());
            ProductStockEntity existStock = productStockMapper.selectOne(stockWhereWrapper);

            updateStock.setPassageStock(existStock.getPassageStock() - passageStockFlow.getAmount());
            stockWhereWrapper.eq(ProductStockEntity::getPassageStock, existStock.getPassageStock());
            if (updateStock.getPassageStock() >= 0) {
                productStockMapper.update(updateStock, stockWhereWrapper);
            }
        }
    }
}
